#ifndef PROGRAM_HPP
#define PROGRAM_HPP

#include "Shader.hpp"

#include <GL/glew.h>
#include <string>

#if defined(__GXX_EXPERIMENTAL_CXX0X) || __cplusplus >= 201103L
#  include <unordered_map>
#  include <unordered_set>
#else
#  include <tr1/unordered_map>
#  include <tr1/unordered_set>
#endif

class Program
{
public:
   
  Program();
  virtual ~Program();

  void create();
  
  void attachShader(const Shader * shader);
  void detachShader(const Shader * shader);
  void detachShaders();
  
  void link();
  void use() { glUseProgram(m_handle); }
  
  void postDelete();
  
  GLuint getHandle() const {return m_handle; }
  GLchar * getLog() const {return m_log; }
  
  GLint getUniformLocation(const std::string & name);
  GLint getAttributeLocation(const std::string & name);
  
private:
  
  GLuint m_handle;
  GLchar * m_log;
  
  
  
#if defined(__GXX_EXPERIMENTAL_CXX0X) || __cplusplus >= 201103L
  template <typename K, typename V>
  struct Map {
    typedef std::unordered_map<K, V> type;
  };
  template <typename T>
  struct Set {
    typedef std::unordered_set<T> type;
  };
#else
    template <typename K, typename V>
  struct Map {
    typedef std::tr1::unordered_map<K, V> type;
  };
  template <typename T>
  struct Set {
    typedef std::tr1::unordered_set<T> type;
  };
#endif
  
  Map<std::string, GLint>::type  m_attributeLocations;
  Map<std::string, GLint>::type  m_uniformLocations;
  
  Set<const Shader *>::type  m_shaders;
};

#endif // PROGRAM_HPP
